# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui, uic
from PyQt4.QtCore import QString
from PyQt4.QtGui import QAbstractItemView,QStandardItemModel,QStandardItem
import serial
from serial.tools.list_ports import comports
import cgi
import time
from  serialCon import serialCon
from mavlinkParaDlg import mavlinkParaDlg
from mirrorSerialDlg import mirrorSerialSettingDlg
# import pymav

qtCreatorFile = "hello.ui" # Enter file here.
 
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)


class MyApp(QtGui.QMainWindow, Ui_MainWindow):
    updateMirrorSettingSig = QtCore.pyqtSignal(object)
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)
        ports = []
        if sys.platform == 'win32':
            devices = comports()
            # ports =['COM1','COM2']
            for device in devices:
                ports.append(device.device)
        else: # linux 
            from   serial.tools import list_ports
            devices = list_ports.grep("(USB|ACM|SAC)")
            for device in devices:
                ports.append(device[0])

        self.serialList.addItems(ports)
        # device is the hardware to transmit and receive data
        self.dataexchanger = None
        self.device = None
        self.hexview = False
        # button and textbrowser
        self.openserialBtn.clicked.connect(self.handleOpenSerial)
        self.clearWindowBtn.clicked.connect(self.clearBrowserAndStat)
        self.saveWindowBtn.clicked.connect(self.saveWindowData)
        self.receivetextbrowser.moveCursor(QtGui.QTextCursor.End)
        self.receivetextbrowser.setReadOnly(True)

        self.hexViewBtn.clicked.connect(self.changeViewMode)


        self.serialc =None
        self.textBrowserLength = 0
        self.clearBrowser()
        self.browserMaxLength =  10000
        self.blockCount = 1

        # menu button action
        self.mavlinkParaSet.triggered.connect(self.obtainMavPara)
        self.mirrorSerialSet.triggered.connect(self.mirrorSerialSetting)

        # mavlink related
        self.mavlinkBrowserBlockCount = 1 
        self.mavlinkBrowserTextLength = 0
        self.mavlinkViewButton.toggled.connect(self.mavlinkParseChange)

        # mavlink tree view 
        self.mavlinkTreeView.setSelectionBehavior(QAbstractItemView.SelectRows)
        model = QStandardItemModel()
        model.setHorizontalHeaderLabels(['sysID', u'频率', u'总包数'])
        # sunmodel = QStandardItemModel(model)
        # sunmodel.setHorizontalHeaderLabels(['sd'])
        self.mavlinkTreeModel = model
        self.mavlinkTreeView.setModel(model)
        self.mavlinkTreeView.setUniformRowHeights(True)
        self.mavlinkTreeView.setSortingEnabled(True);  
        # mavlink speed update
        # key: msgID, val: child of tree view 
        self.mavlinkTreeViewList = dict()



    def handleOpenSerial(self):
        self.openserialBtn.clicked.disconnect(self.handleOpenSerial)
        port = str(self.serialList.currentText())
        baudrate = int(self.baudrateList.currentText())
        print  port,baudrate
        # device = serial.Serial(port,baudrate=baudrate)
        try: 
            device = serial.Serial(port,baudrate=baudrate)
        except:
            #print  "Error occured"
            self.statusBar().showMessage(u'打开串口失败')
            self.openserialBtn.clicked.connect(self.handleOpenSerial)
            return
        self.device = device
        self.openserialBtn.setText(QString(u'关闭'))
        self.openserialBtn.clicked.connect(self.handleCloseSerial)
        
        # self.receivetextbrowser.insertHtml(cgi.escape('you are handsome'+str(self.count)))
        # self.count = self.count + 1
        self.statusBar().showMessage(u'打开串口成功')
        fisrtLaunch = True
        if self.serialc is None:
            self.serialc=serialCon(self.device)
            self.serialc.received.connect(self.updateData)
            self.serialc.speedupdate.connect(self.updateSpeed)
            self.serialc.mavlinkParseUpdate.connect(self.updateMavlink)
            self.serialc.mavlinkSpeedUpdate.connect(self.updateMavlinkPkgSpeed)
            self.updateMirrorSettingSig.connect(self.serialc.bufferedserial.updateMirrorSetting)
        else:
            fisrtLaunch = False
            self.serialc.setDevice(self.device)
        # initial at the beginning 
        self.mavlinkParseChange()
        if fisrtLaunch:
            self.serialc.start()
        else:
            self.serialc.restart()

    def handleCloseSerial(self):
        self.openserialBtn.clicked.disconnect(self.handleCloseSerial)
        #print  'close serial'
        if self.serialc is not None:
            self.serialc.stop()
        self.device.close()
        self.device = None
        self.openserialBtn.setText(QString(u'打开'))
        self.openserialBtn.clicked.connect(self.handleOpenSerial)
    
    @QtCore.pyqtSlot(object)
    def updateData(self,data):
        if self.hexview == True:
            data = " ".join("{:02x}".format(ord(c)) for c in data)
            data = data + ' '
        self.receivetextbrowser.moveCursor(QtGui.QTextCursor.End)
        self.receivetextbrowser.textCursor().insertText(data)

        self.textBrowserLength = self.textBrowserLength  + len( data )
        # can't find another way to speed up refreshment. 
        if self.textBrowserLength > self.browserMaxLength*self.blockCount:
            self.receivetextbrowser.textCursor().insertText("\r\n")
            while self.textBrowserLength > self.browserMaxLength*self.blockCount:
                self.blockCount = self.blockCount +1

    @QtCore.pyqtSlot(object)
    def updateMavlink(self,data):
        mavmsgs =data[0]
        abandonedData =  data[1]
        strdata = ''
        for mavmsg in mavmsgs:
            strdata+=(cgi.escape(str(mavmsg['msgid'])+' '))
        
        self.mavlinkbrowser.moveCursor(QtGui.QTextCursor.End)
        self.mavlinkbrowser.textCursor().insertText(strdata)
        self.mavlinkBrowserTextLength = self.mavlinkBrowserTextLength + len(strdata)
        if self.mavlinkBrowserTextLength > self.browserMaxLength*self.mavlinkBrowserBlockCount:
            self.mavlinkbrowser.moveCursor(QtGui.QTextCursor.End)
            self.mavlinkbrowser.textCursor().insertText("\r\n")
            while self.mavlinkBrowserTextLength > self.browserMaxLength*self.mavlinkBrowserBlockCount:
                self.mavlinkBrowserBlockCount = self.mavlinkBrowserBlockCount +1
        
        self.mavDataAmountLabel.setText(str(self.serialc.mavlinkManager.mavlinkCount))

        #abandoned count 
        self.abandonedCountLabel.setText(str(abandonedData))

    @QtCore.pyqtSlot(object)
    def updateSpeed(self,data):
        # #print  'set speed'
        # #print  data
        instSpeed= data[0]
        totalSpeed=data[1]
        dataAmount = data[2]
        self.speedlabel.setText('%0.3f'%instSpeed+'/'+'%0.3f'%totalSpeed)
        self.dataAmountLabel.setText('%d'%dataAmount)

    @QtCore.pyqtSlot(object)
    def updateMavlinkPkgSpeed(self,data):
        # print "mavlink Speed update"
        msgReceiveTimelist = data[0]
        speedData  = data[1]
        mavlinkPkgSpeed_of_sys = data[2]
        mavlinkBytesSpeed_of_sys = data[3] 
        dataReceiveCount_of_sysID = data[4]
        pkgReceiveCount_of_sysID = data[5]

        # print "i updates"
        import pymav
        for sysID, val in msgReceiveTimelist.iteritems():
            # print "i am in here!!"
            # print key  
            childText = "#"+str(sysID) + " s(p/b):"+"%0.2f"%(mavlinkPkgSpeed_of_sys[sysID]) + '/'+ "%0.2f"%(mavlinkBytesSpeed_of_sys[sysID])+"; c(p/b):"+"%d"%pkgReceiveCount_of_sysID[sysID] + '/'+  "%d"%dataReceiveCount_of_sysID[sysID]

            if (self.mavlinkTreeViewList.has_key(sysID)):
                # print "i already have this"
                for msgID, rectimes in msgReceiveTimelist[sysID].iteritems():
                    if self.mavlinkTreeViewList[sysID].has_key(msgID):
                        child1  = self.mavlinkTreeViewList[sysID][msgID][0]
                        child2  = self.mavlinkTreeViewList[sysID][msgID][1]
                        child3  = self.mavlinkTreeViewList[sysID][msgID][2]
                        # child1  .setText("#"+str(msgID))
                        child2  .setText("%0.2f"%speedData[sysID][msgID])
                        child3  .setText(str(len(rectimes)))
                        child = self.mavlinkTreeViewList[sysID]['child']
                        child.setText(childText)
                        # child.removeRow(0)
                        # child.appendRow([child1,child2,child3])
                    else:
                        child = self.mavlinkTreeViewList[sysID]['child']
                        child.setText(childText)
                        if pymav.mavlink_map.has_key(msgID):
                            child1 =  QStandardItem("#"+str(msgID)+"_"+pymav.mavlink_map[msgID].name)
                        else:
                            child1  = QStandardItem("#"+str(msgID))
                        child2  = QStandardItem("%0.2f"%speedData[sysID][msgID])
                        child3  = QStandardItem(str(len(rectimes)))
                        child.appendRow([child1,child2,child3])
                        self.mavlinkTreeViewList[sysID][msgID] = [child1,child2,child3]
            else:
                # # print "i am in here"
                child  = QStandardItem(childText)
                # # self.mavlinkTreeModel.appendRow()
                firstinclude = True
                for msgID, rectimes in msgReceiveTimelist[sysID].iteritems():
                    if pymav.mavlink_map.has_key(msgID):
                        child1 =  QStandardItem("#"+str(msgID)+"_"+pymav.mavlink_map[msgID].name)
                    else:
                        child1  = QStandardItem("#"+str(msgID))
                    child2  = QStandardItem("%0.2f"%speedData[sysID][msgID])
                    child3  = QStandardItem(str(len(rectimes)))
                    child.appendRow([child1,child2,child3])
                    # model.appendRow(child)
                    if firstinclude: 
                        self.mavlinkTreeModel.appendRow(child)
                        firstinclude = False
                    # self.mavlinkTreeView.setModel(self.mavlinkTreeModel)
                    if self.mavlinkTreeViewList.has_key(sysID):
                        self.mavlinkTreeViewList[sysID][msgID] = [child1,child2,child3]
                    else:
                        self.mavlinkTreeViewList[sysID]= {msgID:[child1,child2,child3]}
                        self.mavlinkTreeViewList[sysID]['child']=child

    def clearBrowser(self):
        self.receivetextbrowser.clear()   
        self.textBrowserLength = 0
            
    def clearBrowserAndStat(self):
        self.clearBrowser()
        if self.serialc is not None:
            self.serialc.clearStat()
        self.speedlabel.setText('/')
        self.dataAmountLabel.setText('')


    def obtainMavPara(self):
        data = mavlinkParaDlg.getPara(parent=self)
        # print data
    @QtCore.pyqtSlot(object)
    def mirrorSerialSetting(self):
        if self.device is not None:
            currentPort= self.serialList.currentText()
            ports = []
            if sys.platform =="win32":
                devices = comports()
                
                for device in devices:
                    port = device.device
                    if port != self.serialList.currentText():
                        ports.append(port) 
            else:
                from   serial.tools import list_ports
                devices = list_ports.grep("(USB|ACM|SAC)")
                for device in devices:
                    port = device[0]
                    if port != self.serialList.currentText():
                        ports.append(port)
            data ={
                "currentPort" : currentPort ,
                "avaliablePorts":ports,
                "bidirection" : True,
                "mavlinkStyle":False,
                'parent':self
            }
            returnedData = mirrorSerialSettingDlg.getPara(data)
            if returnedData[1] == True:
                # valid response
                data = returnedData[0]
                mirrorPort = data['mirrorPort']
                baudrate = self.device.baudrate
                try: 
                    device = serial.Serial(mirrorPort,baudrate=baudrate)
                except:
                    #print  "Error occured"
                    self.statusBar().showMessage(u'打开转发串口失败')
                    self.openserialBtn.clicked.connect(self.handleOpenSerial)
                    return
                print "emit signal"
                data['mirrorDevice']= device 
                self.updateMirrorSettingSig.emit(data)
        else:
            self.statusBar().showMessage(u'尚未打开串口')


    def mavlinkParseChange(self):
        if self.serialc is not None:
            self.serialc.swithMavlinkMode(self.mavlinkViewButton.isChecked())
    
    def saveWindowData(self):
        # should we save data ?
        if self.serialc is not None:
            if self.serialc.bufferedserial.totalBufferLength() != 0:
                defaultLogfileName = time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime())+'.log'
                name = QtGui.QFileDialog.getSaveFileName(self, 'Save File',defaultLogfileName)
                if len(name) != 0:
                    try:
                        f = open(name,'w')
                        data = self.serialc.bufferedserial.dump()
                        print len(data)
                        f.write(data)
                        f.close()
                        self.statusBar().showMessage(u'文件发送成功')
                    except:
                        self.statusBar().showMessage(u'文件发送失败')
            else:
                self.statusBar().showMessage(u'没有数据保存')
        else:
            self.statusBar().showMessage(u'尚未打开过串口')
    def changeViewMode(self):
        '''
        change either hex or text view
        '''
        if self.hexview==False:
            self.hexview = True
            self.hexViewBtn.setText(QString(u'文本显示'))
            if self.serialc is not None:
                data = self.serialc.bufferedserial.dump()
                self.clearBrowser()
                self.updateData(data)
        else:
            self.hexview=False
            self.hexViewBtn.setText(QString(u'十六进制显示'))
            if self.serialc is not None:
                data = self.serialc.bufferedserial.dump()
                self.clearBrowser()
                self.updateData(data)



if __name__ == "__main__":  
    app = QtGui.QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())